﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Utils.Encryption
{
    /// <summary>
    /// Aes加密解密
    /// AES 向量长度为 16位
    /// AES 密钥长度为 32位
    /// </summary>
    public class AesHelper
    {

        //public static byte[] _IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

        //默认密钥向量   
        private static readonly string DefaultIv = "Da4￥3+*%=！41HodklD541";
        /// <summary>
        /// 默认Key
        /// </summary>
        private static readonly string DefaultKey = "#@iST~&i+DaFGdd^544#$d^++2@#6@id";


        /// <summary>
        ///  Aes 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key">长度至少为 32</param>
        /// <param name="iv">长度至少为 16</param>
        /// <returns>byte[]</returns>
        public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
        {
            if (key == null || key.Length < 32)
            {
                throw new ArgumentNullException("密钥长度不足32位");
            }
            if (iv == null || iv.Length < 16)
            {
                throw new ArgumentNullException("向量长度不足32位");
            }

            // Byte[] plainBytes = Encoding.UTF8.GetBytes(Data);

            Byte[] bKey = new Byte[32];
            // Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
            Array.Copy(key, bKey, bKey.Length);
            Byte[] biv = new Byte[16];
            //  Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
            Array.Copy(iv, biv, biv.Length);
            Byte[] ebyte = null; // 加密后的密文  

            Rijndael aes = Rijndael.Create();
            try
            {
                // 开辟一块内存流  
                using (MemoryStream memory = new MemoryStream())
                {
                    // 把内存流对象包装成加密流对象  
                    using (
                        CryptoStream encryptor = new CryptoStream(memory, aes.CreateEncryptor(bKey, biv),
                            CryptoStreamMode.Write))
                    {
                        // 明文数据写入加密流  
                        encryptor.Write(data, 0, data.Length);
                        encryptor.FlushFinalBlock();

                        ebyte = memory.ToArray();
                    }
                }
            }

            catch
            {
                ebyte = null;
            }
            finally
            {
                aes.Clear();
            }
            // return Convert.ToBase64String(str);
            return ebyte;
        }
        /// <summary>
        /// Aes 解密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key">长度至少为 32</param>
        /// <param name="iv">长度至少为 16</param>
        /// <returns>byte[]</returns>
        public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
        {
            if (key == null || key.Length < 32)
            {
                throw new ArgumentNullException("密钥长度不足32位");
            }
            if (iv == null || iv.Length < 16)
            {
                throw new ArgumentNullException("向量长度不足32位");
            }
            // Byte[] encryptedBytes = Convert.FromBase64String(Data);
            Byte[] bKey = new Byte[32];
            // Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
            Array.Copy(key, bKey, bKey.Length);
            Byte[] biv = new Byte[16];
            //Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
            Array.Copy(iv, biv, biv.Length);
            Byte[] dbyte = null; // 解密后的明文  

            Rijndael aes = Rijndael.Create();
            try
            {
                //// 开辟一块内存流，存储密文  
                //using (MemoryStream memory = new MemoryStream(data))
                //{
                //    // 把内存流对象包装成加密流对象  
                //    using (CryptoStream Decryptor = new CryptoStream(memory,
                //    aes.CreateDecryptor(bKey, bVector),
                //    CryptoStreamMode.Read))
                //    {
                //        // 明文存储区  
                //        using (MemoryStream originalMemory = new MemoryStream())
                //        {
                //            Byte[] Buffer = new Byte[1024];
                //            Int32 readBytes = 0;
                //            while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
                //            {
                //                originalMemory.Write(Buffer, 0, readBytes);
                //            }

                //            dbyte = originalMemory.ToArray();
                //        }
                //    }
                //}

                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(bKey, biv), CryptoStreamMode.Write))
                    {
                        cStream.Write(data, 0, data.Length);
                        cStream.FlushFinalBlock();
                        dbyte = mStream.ToArray();
                    }
                }

            }
            catch
            {
                dbyte = null;
            }
            finally
            {
                aes.Clear();
            }
            // return Encoding.UTF8.GetString(dbyte);
            return dbyte;
        }



        public static byte[] EncryptStringToBytes_Aes(byte[] data, byte[] key, byte[] iv)
        {
            // Check arguments.
            //if (string.IsNullOrWhiteSpace(str))
            //    throw new ArgumentNullException("str");
            //if (Key == null || Key.Length <= 0)
            //    throw new ArgumentNullException("Key");
            //if (IV == null || IV.Length <= 0)
            //    throw new ArgumentNullException("Key");
            byte[] encrypted;
            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = key;
                aesAlg.IV = iv;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            //Write all data to the stream.
                            swEncrypt.Write(data);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }


            // Return the encrypted bytes from the memory stream.
            return encrypted;

        }

        public static string DecryptStringFromBytes_Aes(byte[] data, byte[] key, byte[] iv)
        {
            // Check arguments.
            //if (str == null || str.Length <= 0)
            //    throw new ArgumentNullException("cipherText");
            //if (key == null || key.Length <= 0)
            //    throw new ArgumentNullException("Key");
            //if (IV == null || IV.Length <= 0)
            //    throw new ArgumentNullException("Key");

            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;

            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = key;
                aesAlg.IV = iv;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(data))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            // Read the decrypted bytes from the decrypting 
                            //stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }

            }

            return plaintext;
        }

        private static string Nkey = "";
        private static string Niv = "";
        /// <summary>
        ///处理密钥和向量，防止长度不足引起错误
        /// </summary>
        /// <param name="key">密钥</param>
        /// <param name="iv">向量</param>
        private static void HandleKeyAndIv(string key, string iv)
        {
            Nkey = key.Trim();
            if (Nkey.Length < 32)
            {
                Nkey = Nkey + DefaultKey.Substring(0, 32 - Nkey.Length);
            }

            Niv = iv.Trim();
            if (Niv.Length < 16)
            {
                Niv = Niv + DefaultIv.Substring(0, 16 - Niv.Length);
            }
        }

        /// <summary>
        /// Aes 加密
        /// </summary>
        /// <param name="data">需要加密的字符串</param>
        /// <param name="key">密钥</param>
        /// <param name="iv">向量</param>
        /// <returns>string</returns>
        public static string Encrypt(string data, string key, string iv)
        {
            HandleKeyAndIv(key, iv);
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            var ebyte = Encrypt(Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(Nkey), Encoding.UTF8.GetBytes(Niv));
            return Convert.ToBase64String(ebyte);
        }
        /// <summary>
        /// Aes 解密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key">密钥</param>
        /// <param name="iv">向量</param>
        /// <returns>string</returns>
        public static string Decrypt(string data, string key, string iv)
        {
            HandleKeyAndIv(key, iv);
            var ebyte = Decrypt(Convert.FromBase64String(data), Encoding.UTF8.GetBytes(Nkey), Encoding.UTF8.GetBytes(Niv));
            return Encoding.UTF8.GetString(ebyte);
        }

        /// <summary>
        ///  Aes 加密
        /// </summary>
        /// <param name="data">需要加密的字符串</param>
        /// <param name="key">密钥</param>
        /// <returns>string</returns>
        public static string Encrypt(string data, string key)
        {
            HandleKeyAndIv(key, DefaultIv);
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            var ebyte = Encrypt(Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(Nkey), Encoding.UTF8.GetBytes(Niv));
            return Convert.ToBase64String(ebyte);
        }
        /// <summary>
        /// Aes 解密
        /// </summary>
        /// <param name="data">需要解密字符串</param>
        /// <param name="key">密钥</param>
        /// <returns>string</returns>
        public static string Decrypt(string data, string key)
        {
            HandleKeyAndIv(key, DefaultIv);
            var ebyte = Decrypt(Convert.FromBase64String(data), Encoding.UTF8.GetBytes(Nkey), Encoding.UTF8.GetBytes(Niv));
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            return Encoding.UTF8.GetString(ebyte);
        }
        /// <summary>
        ///  Aes 加密
        /// </summary>
        /// <param name="data">需要加密的字符串</param>
        /// <returns>string</returns>
        public static string Encrypt(string data)
        {
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            var ebyte = Encrypt(Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(DefaultKey), Encoding.UTF8.GetBytes(DefaultIv));
            return Convert.ToBase64String(ebyte);
        }
        /// <summary>
        /// Aes 解密
        /// </summary>
        /// <param name="data">需要解密字符串</param>
        /// <returns>string</returns>
        public static string Decrypt(string data)
        {
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            var ebyte = Decrypt(Convert.FromBase64String(data), Encoding.UTF8.GetBytes(DefaultKey), Encoding.UTF8.GetBytes(DefaultIv));
            return Encoding.UTF8.GetString(ebyte);
        }

        #region Aes 无向量加密解密
        /// <summary>
        /// Aes 无向量加密
        /// </summary>
        /// <param name="data">加密byte[]</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static byte[] EncryptNoIv(byte[] data, byte[] key)
        {
            if (key == null || key.Length < 32)
            {
                throw new ArgumentNullException("密钥长度不足32位");
            }
            RijndaelManaged aes = new RijndaelManaged();
            // byte[] plainBytes = Encoding.UTF8.GetBytes(Data);
            //Byte[] bKey = new Byte[32];
            //Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);

            aes.Mode = CipherMode.ECB;
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = 128;
            //aes.Key = _key;  
            aes.Key = key;
            //aes.IV = _iV; 
            try
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(data, 0, data.Length);
                        cryptoStream.FlushFinalBlock();
                        return mStream.ToArray();
                    }
                }
            }
            finally
            {
                aes.Clear();
            }
        }
        /// <summary>
        /// Ase 无向量解密
        /// </summary>
        /// <param name="data">解密 byte[]</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static byte[] DecryptNoIv(byte[] data, byte[] key)
        {
            if (key == null || key.Length < 32)
            {
                throw new ArgumentNullException("密钥长度不足32位");
            }
            //Byte[] encryptedBytes = Convert.FromBase64String(Data);
            //Byte[] bKey = new Byte[32];
            //Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);


            //mStream.Write( encryptedBytes, 0, encryptedBytes.Length );  
            //mStream.Seek( 0, SeekOrigin.Begin );  
            RijndaelManaged aes = new RijndaelManaged();
            aes.Mode = CipherMode.ECB;
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = 128;
            aes.Key = key;
            //aes.IV = _iV;  

            try
            {
                using (MemoryStream mStream = new MemoryStream(data))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
                    {
                        byte[] tmp = new byte[data.Length + 32];
                        int len = cryptoStream.Read(tmp, 0, data.Length + 32);
                        byte[] ret = new byte[len];
                        Array.Copy(tmp, 0, ret, 0, len);
                        return ret;
                    }
                }
            }
            finally
            {
                aes.Clear();
            }
        }
        /// <summary>
        /// Aes 无向量加密
        /// </summary>
        /// <param name="data">需要加密的字符串</param>
        /// <param name="key">密钥</param>
        /// <returns>string</returns>
        public static string EncryptNoIv(string data, string key)
        {
            var nkey = key;
            if (nkey.Length < 32)
            {
                nkey = nkey + DefaultKey.Substring(0, 32 - nkey.Length);
            }
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            var ebyte = EncryptNoIv(Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(nkey));
            return Convert.ToBase64String(ebyte);
        }
        /// <summary>
        /// Ase 无向量解密
        /// </summary>
        /// <param name="data">需要解密字符串</param>
        /// <param name="key">密钥</param>
        /// <returns>string</returns>
        public static string DecryptNoIv(string data, string key)
        {
            var nkey = key;
            if (nkey.Length < 32)
            {
                nkey = nkey + DefaultKey.Substring(0, 32 - nkey.Length);
            }
            var ebyte = DecryptNoIv(Convert.FromBase64String(data), Encoding.UTF8.GetBytes(nkey));
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            return Encoding.UTF8.GetString(ebyte);
        }
        /// <summary>
        /// Aes 无向量加密
        /// </summary>
        /// <param name="data">需要加密的字符串</param>
        /// <returns>string</returns>
        public static string EncryptNoIv(string data)
        {
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            var ebyte = EncryptNoIv(Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(DefaultKey));
            return Convert.ToBase64String(ebyte);
        }
        /// <summary>
        /// Ase 无向量解密
        /// </summary>
        /// <param name="data">需要解密字符串</param>
        /// <returns>string</returns>
        public static string DecryptNoIv(string data)
        {
            var ebyte = DecryptNoIv(Convert.FromBase64String(data), Encoding.UTF8.GetBytes(DefaultKey));
#if Standard
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
            return Encoding.UTF8.GetString(ebyte);
        }

        #endregion

        ///// <summary>  
        ///// AES加密  
        ///// </summary>  
        ///// <param name="Data">被加密的明文</param>  
        ///// <param name="Key">密钥</param>  
        ///// <param name="Vector">向量</param>  
        ///// <returns>密文</returns>  
        //public static String Encrypt(String Data, String Key, String Vector)
        //{
        //    Byte[] plainBytes = Encoding.UTF8.GetBytes(Data);

        //    Byte[] bKey = new Byte[32];
        //    Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
        //    Byte[] bVector = new Byte[16];
        //    Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);

        //    Byte[] Cryptograph = null; // 加密后的密文  

        //    Rijndael Aes = Rijndael.Create();
        //    try
        //    {
        //        // 开辟一块内存流  
        //        using (MemoryStream Memory = new MemoryStream())
        //        {
        //            // 把内存流对象包装成加密流对象  
        //            using (CryptoStream Encryptor = new CryptoStream(Memory,
        //             Aes.CreateEncryptor(bKey, bVector),
        //             CryptoStreamMode.Write))
        //            {
        //                // 明文数据写入加密流  
        //                Encryptor.Write(plainBytes, 0, plainBytes.Length);
        //                Encryptor.FlushFinalBlock();

        //                Cryptograph = Memory.ToArray();
        //            }
        //        }
        //    }
        //    catch
        //    {
        //        Cryptograph = null;
        //    }

        //    return Convert.ToBase64String(Cryptograph);
        //}

        ///// <summary>  
        ///// AES解密  
        ///// </summary>  
        ///// <param name="Data">被解密的密文</param>  
        ///// <param name="Key">密钥</param>  
        ///// <param name="Vector">向量</param>  
        ///// <returns>明文</returns>  
        //public static String Decrypt(String Data, String Key, String Vector)
        //{
        //    Byte[] encryptedBytes = Convert.FromBase64String(Data);
        //    Byte[] bKey = new Byte[32];
        //    Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
        //    Byte[] bVector = new Byte[16];
        //    Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);

        //    Byte[] original = null; // 解密后的明文  

        //    Rijndael Aes = Rijndael.Create();
        //    try
        //    {
        //        // 开辟一块内存流，存储密文  
        //        using (MemoryStream Memory = new MemoryStream(encryptedBytes))
        //        {
        //            // 把内存流对象包装成加密流对象  
        //            using (CryptoStream Decryptor = new CryptoStream(Memory,
        //            Aes.CreateDecryptor(bKey, bVector),
        //            CryptoStreamMode.Read))
        //            {
        //                // 明文存储区  
        //                using (MemoryStream originalMemory = new MemoryStream())
        //                {
        //                    Byte[] Buffer = new Byte[1024];
        //                    Int32 readBytes = 0;
        //                    while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
        //                    {
        //                        originalMemory.Write(Buffer, 0, readBytes);
        //                    }

        //                    original = originalMemory.ToArray();
        //                }
        //            }
        //        }
        //    }
        //    catch
        //    {
        //        original = null;
        //    }
        //    return Encoding.UTF8.GetString(original);
        //}



        ///// <summary>  
        ///// AES加密(无向量)  
        ///// </summary>  
        ///// <param name="plainBytes">被加密的明文</param>  
        ///// <param name="key">密钥</param>  
        ///// <returns>密文</returns>  
        //public static string Encrypt(String Data, String Key)
        //{
        //    MemoryStream mStream = new MemoryStream();
        //    RijndaelManaged aes = new RijndaelManaged();

        //    byte[] plainBytes = Encoding.UTF8.GetBytes(Data);
        //    Byte[] bKey = new Byte[32];
        //    Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);

        //    aes.Mode = CipherMode.ECB;
        //    aes.Padding = PaddingMode.PKCS7;
        //    aes.KeySize = 128;
        //    //aes.Key = _key;  
        //    aes.Key = bKey;
        //    //aes.IV = _iV;  
        //    CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
        //    try
        //    {
        //        cryptoStream.Write(plainBytes, 0, plainBytes.Length);
        //        cryptoStream.FlushFinalBlock();
        //        return Convert.ToBase64String(mStream.ToArray());
        //    }
        //    finally
        //    {
        //        cryptoStream.Close();
        //        mStream.Close();
        //        aes.Clear();
        //    }
        //}


        ///// <summary>  
        ///// AES解密(无向量)  
        ///// </summary>  
        ///// <param name="encryptedBytes">被加密的明文</param>  
        ///// <param name="key">密钥</param>  
        ///// <returns>明文</returns>  
        //public static string Decrypt(String Data, String Key)
        //{
        //    Byte[] encryptedBytes = Convert.FromBase64String(Data);
        //    Byte[] bKey = new Byte[32];
        //    Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);

        //    MemoryStream mStream = new MemoryStream(encryptedBytes);
        //    //mStream.Write( encryptedBytes, 0, encryptedBytes.Length );  
        //    //mStream.Seek( 0, SeekOrigin.Begin );  
        //    RijndaelManaged aes = new RijndaelManaged();
        //    aes.Mode = CipherMode.ECB;
        //    aes.Padding = PaddingMode.PKCS7;
        //    aes.KeySize = 128;
        //    aes.Key = bKey;
        //    //aes.IV = _iV;  
        //    CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
        //    try
        //    {
        //        byte[] tmp = new byte[encryptedBytes.Length + 32];
        //        int len = cryptoStream.Read(tmp, 0, encryptedBytes.Length + 32);
        //        byte[] ret = new byte[len];
        //        Array.Copy(tmp, 0, ret, 0, len);
        //        return Encoding.UTF8.GetString(ret);
        //    }
        //    finally
        //    {
        //        cryptoStream.Close();
        //        mStream.Close();
        //        aes.Clear();
        //    }
        //}
    }
}
